/*
    asyframe for asyframe@gmail.com

    Copyright (C) 2011, asyframe@gmail.com, http://asyframe.googlecode.com/

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "stdafx.h"
#include "ConstDef.h"
#include "Common/Logger.h"
#include "Common/Interface.h"
#include "Common/ThreadHandler.h"
#include "Common/WorkerBase.h"
#include "Common/AppBase.h"
#include "Common/ActorBase.h"
#include "Network/AcceptHandler.h"

namespace asyframe
{
	AcceptHandlerContext::AcceptHandlerContext()
		:pTcpSocket_(),pAcceptedActor_()
	{

	}

	AcceptHandlerContext::AcceptHandlerContext( boost::shared_ptr<AcceptHandlerContext> _pAcceptHandlerContext )
		:HandlerContextBase(_pAcceptHandlerContext),pTcpSocket_(_pAcceptHandlerContext->pTcpSocket_),pAcceptedActor_(_pAcceptHandlerContext->pAcceptedActor_)
	{

	}

	AcceptHandlerContext::~AcceptHandlerContext()
	{
		pTcpSocket_.reset();
		pAcceptedActor_.reset();
	}

///////////////////////////////////////////////////////////////////////////////

	IAcceptAction::IAcceptAction()
	{

	}

	IAcceptAction::~IAcceptAction()
	{

	}

	retT IAcceptAction::onAccept( boost::shared_ptr<AcceptHandlerContext> _pAcceptHandlerContext, const boost::system::error_code& e, std::size_t _timeoutCount )
	{
		R(handleTimeout(_pAcceptHandlerContext, e, _timeoutCount));
		RETSUCCESS;
	}

///////////////////////////////////////////////////////////////////////////////

	AcceptHandler::AcceptHandler()
		:HandlerBase(),pAcceptor_(),pLocalEndpoint_()
	{

	}

	AcceptHandler::~AcceptHandler()
	{
		pAcceptor_.reset();
		pLocalEndpoint_.reset();
	}

	retT AcceptHandler::bind( boost::shared_ptr<WorkerBase> _pWorker )
	{
		if(!_pWorker)
			RET(ERROR_COMMON_SHARED_PTR_NULL);
		R(HandlerBase::bind(_pWorker));
		pAcceptor_.reset(new boost::asio::ip::tcp::acceptor(*_pWorker->getIoService()));
		if(pLocalEndpoint_)
		{
			pAcceptor_->open(pLocalEndpoint_->protocol());
			pAcceptor_->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
			pAcceptor_->bind(*pLocalEndpoint_);
			pAcceptor_->listen();
		}
		RETSUCCESS;
	}

	retT AcceptHandler::asyncAccept( boost::shared_ptr<boost::asio::ip::tcp::socket> _pTcpSocket, boost::shared_ptr<AcceptHandlerContext> _pAcceptHandlerContext, BaseCallBackFunType _acceptCallBackFun )
	{
		if(_acceptCallBackFun == NULL)
		{
			if(boost::shared_ptr<IAcceptAction> pIAcceptAction = boost::dynamic_pointer_cast<IAcceptAction>(pHandlerOwner_.lock()))
			{
				_acceptCallBackFun = boost::bind(&IAcceptAction::onAccept, pIAcceptAction, _pAcceptHandlerContext, _1, _2);
			}
			else
				RET(ERROR_HANDLERBASE_HANDLEROWNER_NOT_EXIST);
		}
		R(operationStart(_pAcceptHandlerContext, _acceptCallBackFun));
		if(!_pTcpSocket || !pAcceptor_)
			RET(ERROR_COMMON_SHARED_PTR_NULL);
		if(_pAcceptHandlerContext)
		{
			if(!_pAcceptHandlerContext->pTcpSocket_)
				_pAcceptHandlerContext->pTcpSocket_ = _pTcpSocket;
		}
		pAcceptor_->async_accept(_pTcpSocket->lowest_layer(),
			boost::bind(_acceptCallBackFun,
			boost::asio::placeholders::error,
			0));
		RETSUCCESS;
	}

	void AcceptHandler::setLocalEndpoint( boost::shared_ptr<boost::asio::ip::tcp::endpoint> _pLocalEndpoint )
	{
		pLocalEndpoint_ = _pLocalEndpoint;
	}

	boost::shared_ptr<boost::asio::ip::tcp::endpoint> AcceptHandler::getLocalEndpoint()
	{
		return pLocalEndpoint_;
	}

	boost::shared_ptr<boost::asio::ip::tcp::acceptor> AcceptHandler::getAcceptor()
	{
		return pAcceptor_;
	}

	retT AcceptHandler::close()
	{
		R(HandlerBase::close());
		if(pAcceptor_)
			pAcceptor_->close();
		RETSUCCESS;
	}

	retT AcceptHandler::reset()
	{
		if(pAcceptor_)
			pAcceptor_->close();
		R(HandlerBase::reset());
		RETSUCCESS;
	}

//////////////////////////////////////////////////////////////////////////////////////

	IAcceptableActor::IAcceptableActor()
	{

	}

	IAcceptableActor::~IAcceptableActor()
	{

	}

//////////////////////////////////////////////////////////////////////////////////////

	ProAcceptHandler::ProAcceptHandler()
		:pTcpConnectionActorMgr_()
	{

	}

	ProAcceptHandler::~ProAcceptHandler()
	{
		pTcpConnectionActorMgr_.reset();
	}

	retT ProAcceptHandler::onAccept( boost::shared_ptr<AcceptHandlerContext> _pAcceptHandlerContext, const boost::system::error_code& e, std::size_t _timeoutCount )
	{
		_R(IAcceptAction::onAccept(_pAcceptHandlerContext, e, _timeoutCount))
		{
			if(ret.status_ && (ret.status_&NOLOGMSK) != INFO_IACTIONBASE_TIMER_OPERATION_ABORT && _pAcceptHandlerContext && _pAcceptHandlerContext->pAcceptedActor_)
				R(_pAcceptHandlerContext->pAcceptedActor_->post(boost::bind(&ActorBase::close, _pAcceptHandlerContext->pAcceptedActor_)));
		}R_
		if(_pAcceptHandlerContext && _pAcceptHandlerContext->pAcceptedActor_)
		{
			if(!e)
			{
				R(_pAcceptHandlerContext->pAcceptedActor_->post(boost::bind(&ActorBase::start, _pAcceptHandlerContext->pAcceptedActor_)));
			}
			else
			{
				R(_pAcceptHandlerContext->pAcceptedActor_->post(boost::bind(&ActorBase::close, _pAcceptHandlerContext->pAcceptedActor_)));
			}
		}
		if(_pAcceptHandlerContext)
			_pAcceptHandlerContext->pTcpSocket_.reset();
		if(e == boost::asio::error::operation_aborted)
			RETSUCCESS;
		if(e)
		{
			LOG_INFO(boost::format( "errorNo %1% : %2% in %3% %4% %5%" ) % e.value() % e.message() % __FUNCTION__ % __FILE__ % __LINE__);
		}
		R(acceptOne());
		RETSUCCESS;
	}

	retT ProAcceptHandler::attachTcpConnectionActorMgr( boost::shared_ptr<ActorMgrBase> _pTcpConnectionActorMgr )
	{
		pTcpConnectionActorMgr_ = _pTcpConnectionActorMgr;
		RETSUCCESS;
	}

	retT ProAcceptHandler::startAccept()
	{
		R(acceptOne());
		RETSUCCESS;
	}

	retT ProAcceptHandler::acceptOne()
	{
		boost::shared_ptr<AcceptHandlerContext> pAcceptHandlerContext(new AcceptHandlerContext());
		boost::shared_ptr<ActorBase> pAcceptedActor;
		if(boost::shared_ptr<ActorMgrBase> pTcpConnectionActorMgr = pTcpConnectionActorMgr_.lock())
		{
			R(pTcpConnectionActorMgr->makeActor(pAcceptedActor));
		}
		else
		{
			RET(ERROR_COMMON_SHARED_PTR_NULL);
		}
		pAcceptHandlerContext->pAcceptedActor_ = pAcceptedActor;
		R(asyncAccept(boost::dynamic_pointer_cast<IAcceptableActor>(pAcceptedActor)->getTcpSocket(),
			pAcceptHandlerContext,
			boost::bind(&ProAcceptHandler::onAccept,
			boost::dynamic_pointer_cast<ProAcceptHandler>(shared_from_this()),
			pAcceptHandlerContext, _1, _2)));
		RETSUCCESS;
	}
} /* namespace asyframe */
